/**
 * @p.md
 * 
 * Consul集群提供者
 * 使用Consul实现集群成员管理和服务发现
 */
import { EventEmitter } from 'events';
import { 
  ClusterProvider, 
  ClusterProviderEvent, 
  ClusterProviderEventType 
} from '../clusterProvider';
import { Cluster } from '../cluster';
import { Member, MemberStatus } from '../clusterConfig';

/**
 * 默认Consul服务选项
 */
const DEFAULT_TTL = '10s';
const DEFAULT_DEREGISTER_CRITICAL_SERVICE_AFTER = '30s';
const DEFAULT_CONSUL_HTTP_CHECK_INTERVAL = '5s';

/**
 * Consul提供者配置
 */
export interface ConsulProviderConfig {
  /**
   * Consul服务地址，默认为localhost:8500
   */
  consulAddress?: string;
  
  /**
   * Consul ACL令牌
   */
  aclToken?: string;
  
  /**
   * 服务存活时间(TTL)
   */
  serviceTTL?: string;
  
  /**
   * 心跳间隔(毫秒)
   */
  heartbeatInterval?: number;
  
  /**
   * 重新连接间隔(毫秒)
   */
  reconnectInterval?: number;
  
  /**
   * 服务注销超时
   */
  deregisterCriticalServiceAfter?: string;
  
  /**
   * 服务标签
   */
  serviceTags?: string[];
  
  /**
   * 元数据
   */
  meta?: Record<string, string>;
  
  /**
   * HTTP检查路径
   */
  httpCheckPath?: string;
  
  /**
   * HTTP检查间隔
   */
  httpCheckInterval?: string;
}

/**
 * 默认Consul提供者配置
 */
export const DefaultConsulProviderConfig: ConsulProviderConfig = {
  consulAddress: 'localhost:8500',
  serviceTTL: DEFAULT_TTL,
  heartbeatInterval: 5000,
  reconnectInterval: 3000,
  deregisterCriticalServiceAfter: DEFAULT_DEREGISTER_CRITICAL_SERVICE_AFTER,
  serviceTags: ['protoactor', 'cluster'],
  httpCheckInterval: DEFAULT_CONSUL_HTTP_CHECK_INTERVAL
};

/**
 * Consul集群提供者
 * 使用Consul实现集群成员管理和服务发现
 */
export class ConsulProvider extends EventEmitter implements ClusterProvider {
  /**
   * 集群引用
   */
  private cluster: Cluster | null = null;
  
  /**
   * 成员映射
   */
  private members: Map<string, Member> = new Map();
  
  /**
   * 心跳定时器
   */
  private heartbeatTimer: NodeJS.Timer | null = null;
  
  /**
   * 领导者ID
   */
  private leaderId: string | null = null;
  
  /**
   * 本地节点ID
   */
  private localNodeId: string | null = null;
  
  /**
   * 是否已启动
   */
  private running: boolean = false;
  
  /**
   * 事件监听器列表
   */
  private eventListeners: ((event: ClusterProviderEvent) => void)[] = [];
  
  /**
   * Consul客户端
   * 这是一个简化示例，实际实现需要一个完整的Consul HTTP客户端
   */
  private consulClient: any = null;
  
  /**
   * 服务ID
   */
  private serviceId: string | null = null;
  
  /**
   * 服务键前缀
   */
  private keyPrefix: string = 'protoactor/cluster/';
  
  /**
   * 会话ID
   */
  private sessionId: string | null = null;
  
  /**
   * 构造函数
   * @param config 配置
   */
  constructor(private config: ConsulProviderConfig = DefaultConsulProviderConfig) {
    super();
    this.validateConfig();
    
    // 在真实实现中，这里应该初始化Consul HTTP客户端
    this.consulClient = {
      // 这是一个模拟的Consul客户端，实际实现需要使用第三方库或自定义HTTP客户端
      async createSession(opts: any): Promise<{ID: string}> {
        return { ID: `session-${Date.now()}` };
      },
      
      async renewSession(id: string): Promise<void> {
        // 模拟会话续约
        return;
      },
      
      async registerService(opts: any): Promise<void> {
        // 模拟服务注册
        return;
      },
      
      async updateTTL(checkID: string, status: string, output: string): Promise<void> {
        // 模拟TTL更新
        return;
      },
      
      async deregisterService(serviceId: string): Promise<void> {
        // 模拟服务注销
        return;
      },
      
      async getServices(): Promise<any[]> {
        // 模拟获取服务列表
        return [];
      },
      
      async kv_get(key: string): Promise<any> {
        // 模拟KV获取
        return null;
      },
      
      async kv_set(key: string, value: string, opts: any): Promise<boolean> {
        // 模拟KV设置
        return true;
      },
      
      async kv_del(key: string): Promise<void> {
        // 模拟KV删除
        return;
      }
    };
  }
  
  /**
   * 验证配置
   */
  private validateConfig(): void {
    if (!this.config.consulAddress) {
      this.config.consulAddress = DefaultConsulProviderConfig.consulAddress;
    }
    
    if (!this.config.serviceTTL) {
      this.config.serviceTTL = DefaultConsulProviderConfig.serviceTTL;
    }
    
    if (!this.config.heartbeatInterval) {
      this.config.heartbeatInterval = DefaultConsulProviderConfig.heartbeatInterval;
    }
    
    if (!this.config.reconnectInterval) {
      this.config.reconnectInterval = DefaultConsulProviderConfig.reconnectInterval;
    }
    
    if (!this.config.deregisterCriticalServiceAfter) {
      this.config.deregisterCriticalServiceAfter = 
        DefaultConsulProviderConfig.deregisterCriticalServiceAfter;
    }
  }

  /**
   * 初始化提供者
   * @param cluster 集群引用
   */
  async init(cluster: Cluster): Promise<void> {
    this.cluster = cluster;
    this.localNodeId = cluster.getNodeId();
    this.keyPrefix = `protoactor/cluster/${cluster.getConfig().clusterName}/`;
    
    // 创建Consul会话
    try {
      const sessionResponse = await this.consulClient.createSession({
        Name: `protoactor-session-${this.localNodeId}`,
        TTL: this.config.serviceTTL,
        Behavior: 'delete'
      });
      
      this.sessionId = sessionResponse.ID;
      console.log(`Consul会话已创建: ${this.sessionId}`);
    } catch (error) {
      console.error('创建Consul会话失败:', error);
      throw error;
    }
  }

  /**
   * 启动提供者
   */
  async start(): Promise<void> {
    if (this.running) {
      return;
    }
    
    // 开始心跳检测
    this.startHeartbeat();
    
    // 开始监控成员变化
    this.monitorMemberStatusChanges();
    
    // 尝试选举领导者
    await this.electLeader();
    
    this.running = true;
  }

  /**
   * 关闭提供者
   */
  async shutdown(): Promise<void> {
    if (!this.running) {
      return;
    }
    
    // 停止心跳检测
    this.stopHeartbeat();
    
    // 取消注册服务
    if (this.serviceId) {
      try {
        await this.consulClient.deregisterService(this.serviceId);
      } catch (error) {
        console.error('取消注册服务失败:', error);
      }
    }
    
    // 删除KV数据
    if (this.localNodeId) {
      try {
        await this.consulClient.kv_del(`${this.keyPrefix}members/${this.localNodeId}`);
      } catch (error) {
        console.error('删除成员KV数据失败:', error);
      }
    }
    
    // 释放领导者锁
    if (this.leaderId === this.localNodeId) {
      try {
        await this.consulClient.kv_del(`${this.keyPrefix}leader`);
      } catch (error) {
        console.error('释放领导者锁失败:', error);
      }
    }
    
    this.running = false;
    this.cluster = null;
    this.leaderId = null;
    this.sessionId = null;
  }

  /**
   * 注册成员
   * @param address 地址
   * @param metadata 元数据
   */
  async registerMember(address: string, metadata?: any): Promise<void> {
    if (!this.localNodeId || !this.sessionId) {
      throw new Error('提供者尚未初始化');
    }
    
    // 生成服务ID
    this.serviceId = `protoactor-${this.localNodeId}`;
    
    // 构建服务注册对象
    const serviceRegistration = {
      ID: this.serviceId,
      Name: `protoactor-cluster-${this.cluster?.getConfig().clusterName}`,
      Tags: this.config.serviceTags,
      Meta: {
        ...this.config.meta,
        nodeId: this.localNodeId,
        address,
        ...metadata
      },
      Address: address.split(':')[0],
      Port: parseInt(address.split(':')[1], 10),
      Check: {
        TTL: this.config.serviceTTL,
        DeregisterCriticalServiceAfter: this.config.deregisterCriticalServiceAfter
      }
    };
    
    // 注册服务到Consul
    try {
      await this.consulClient.registerService(serviceRegistration);
      console.log(`服务已注册到Consul: ${this.serviceId}`);
      
      // 将成员信息存储到KV
      const member: Member = {
        id: this.localNodeId,
        address,
        host: address.split(':')[0],
        port: parseInt(address.split(':')[1], 10),
        status: MemberStatus.Alive,
        joinedAt: Date.now(),
        capabilities: new Map(),
        metadata: new Map(Object.entries(metadata || {}))
      };
      
      await this.consulClient.kv_set(
        `${this.keyPrefix}members/${this.localNodeId}`,
        JSON.stringify(member),
        { acquire: this.sessionId }
      );
      
      // 更新本地成员列表
      this.members.set(this.localNodeId, member);
      
      // 触发成员加入事件
      this.emitEvent({
        type: ClusterProviderEventType.MemberJoined,
        member,
        timestamp: Date.now()
      });
      
      // 触发成员可用事件
      this.emitEvent({
        type: ClusterProviderEventType.MemberAvailable,
        member,
        timestamp: Date.now()
      });
    } catch (error) {
      console.error('注册服务到Consul失败:', error);
      throw error;
    }
  }

  /**
   * 取消注册成员
   */
  async unregisterMember(): Promise<void> {
    if (!this.localNodeId || !this.serviceId) {
      return;
    }
    
    const member = this.members.get(this.localNodeId);
    if (!member) {
      return;
    }
    
    // 修改状态为离开
    member.status = MemberStatus.Leaving;
    this.members.set(this.localNodeId, member);
    
    // 触发成员不可用事件
    this.emitEvent({
      type: ClusterProviderEventType.MemberUnavailable,
      member,
      timestamp: Date.now()
    });
    
    // 如果是领导者，释放领导者锁
    if (this.leaderId === this.localNodeId) {
      try {
        await this.consulClient.kv_del(`${this.keyPrefix}leader`);
      } catch (error) {
        console.error('释放领导者锁失败:', error);
      }
    }
    
    // 取消注册服务
    try {
      await this.consulClient.deregisterService(this.serviceId);
      
      // 从KV中删除成员信息
      await this.consulClient.kv_del(`${this.keyPrefix}members/${this.localNodeId}`);
      
      // 从本地成员列表中移除
      this.members.delete(this.localNodeId);
      
      // 触发成员离开事件
      this.emitEvent({
        type: ClusterProviderEventType.MemberLeft,
        member,
        timestamp: Date.now()
      });
    } catch (error) {
      console.error('取消注册服务失败:', error);
    }
  }

  /**
   * 获取所有成员
   */
  async getMembers(): Promise<Member[]> {
    // 刷新成员列表后返回
    await this.refreshMembers();
    return Array.from(this.members.values());
  }

  /**
   * 根据ID获取成员
   * @param memberId 成员ID
   */
  async getMemberById(memberId: string): Promise<Member | null> {
    // 检查本地缓存
    if (this.members.has(memberId)) {
      return this.members.get(memberId) || null;
    }
    
    // 从Consul获取成员信息
    try {
      const result = await this.consulClient.kv_get(`${this.keyPrefix}members/${memberId}`);
      if (!result) {
        return null;
      }
      
      const member = JSON.parse(result.Value);
      // 更新本地缓存
      this.members.set(memberId, member);
      return member;
    } catch (error) {
      console.error(`获取成员${memberId}失败:`, error);
      return null;
    }
  }

  /**
   * 监控成员状态变化
   */
  monitorMemberStatusChanges(): void {
    // 定期从Consul刷新成员列表
    setInterval(async () => {
      await this.refreshMembers();
    }, this.config.heartbeatInterval);
  }

  /**
   * 获取集群元数据
   */
  async getClusterMetadata(): Promise<any> {
    return {
      memberCount: this.members.size,
      leaderId: this.leaderId,
      providerType: 'consul',
      consulAddress: this.config.consulAddress
    };
  }

  /**
   * 检查是否为领导者
   */
  async isLeader(): Promise<boolean> {
    return this.localNodeId === this.leaderId;
  }

  /**
   * 获取领导者
   */
  async getLeader(): Promise<Member | null> {
    if (!this.leaderId) {
      // 如果没有领导者，尝试从Consul获取
      await this.refreshLeader();
    }
    
    if (!this.leaderId) {
      return null;
    }
    
    return this.getMemberById(this.leaderId);
  }

  /**
   * 注册事件监听器
   * @param listener 监听器函数
   */
  registerEventListener(listener: (event: ClusterProviderEvent) => void): void {
    this.eventListeners.push(listener);
  }

  /**
   * 移除事件监听器
   * @param listener 监听器函数
   */
  removeEventListener(listener: (event: ClusterProviderEvent) => void): void {
    const index = this.eventListeners.indexOf(listener);
    if (index !== -1) {
      this.eventListeners.splice(index, 1);
    }
  }

  /**
   * 开始心跳检测
   */
  private startHeartbeat(): void {
    const interval = this.config.heartbeatInterval || DefaultConsulProviderConfig.heartbeatInterval!;
    this.heartbeatTimer = setInterval(() => this.performHeartbeat(), interval);
  }

  /**
   * 停止心跳检测
   */
  private stopHeartbeat(): void {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  /**
   * 执行心跳检测
   */
  private async performHeartbeat(): Promise<void> {
    if (!this.serviceId || !this.sessionId) {
      return;
    }
    
    try {
      // 更新TTL检查
      await this.consulClient.updateTTL(
        `service:${this.serviceId}`,
        'passing',
        'Heartbeat'
      );
      
      // 续约会话
      await this.consulClient.renewSession(this.sessionId);
      
      // 尝试成为领导者（如果没有领导者）
      if (!this.leaderId) {
        await this.electLeader();
      }
    } catch (error) {
      console.error('心跳更新失败:', error);
      
      // 重新创建会话
      this.recreateSession();
    }
  }

  /**
   * 重新创建会话
   */
  private async recreateSession(): Promise<void> {
    try {
      const sessionResponse = await this.consulClient.createSession({
        Name: `protoactor-session-${this.localNodeId}`,
        TTL: this.config.serviceTTL,
        Behavior: 'delete'
      });
      
      this.sessionId = sessionResponse.ID;
      console.log(`Consul会话已重新创建: ${this.sessionId}`);
      
      // 重新注册服务和成员信息
      if (this.localNodeId && this.members.has(this.localNodeId)) {
        const member = this.members.get(this.localNodeId)!;
        await this.registerMember(member.address, member.metadata);
      }
    } catch (error) {
      console.error('重新创建会话失败:', error);
      
      // 延迟重试
      setTimeout(() => this.recreateSession(), this.config.reconnectInterval);
    }
  }

  /**
   * 刷新成员列表
   */
  private async refreshMembers(): Promise<void> {
    try {
      // 从Consul获取所有服务
      const services = await this.consulClient.getServices();
      
      // 筛选出集群服务
      const clusterServices = services.filter(svc => 
        svc.Tags && svc.Tags.includes('protoactor') && 
        svc.Tags.includes('cluster')
      );
      
      // 处理成员加入和状态变更
      for (const svc of clusterServices) {
        const nodeId = svc.Meta?.nodeId;
        if (!nodeId) continue;
        
        const memberStatus = svc.Status === 'passing' ? 
          MemberStatus.Alive : MemberStatus.Unavailable;
        
        const member: Member = {
          id: nodeId,
          address: `${svc.Address}:${svc.Port}`,
          host: svc.Address,
          port: svc.Port,
          status: memberStatus,
          joinedAt: this.members.has(nodeId) ? 
            this.members.get(nodeId)!.joinedAt : Date.now(),
          capabilities: new Map(),
          metadata: new Map(Object.entries(svc.Meta || {}))
        };
        
        // 检查成员是否已存在
        if (this.members.has(nodeId)) {
          const existingMember = this.members.get(nodeId)!;
          
          // 检查状态是否变更
          if (existingMember.status !== memberStatus) {
            // 更新成员状态
            this.members.set(nodeId, member);
            
            // 触发状态变更事件
            this.emitEvent({
              type: ClusterProviderEventType.MemberStatusChanged,
              member,
              timestamp: Date.now(),
              metadata: { oldStatus: existingMember.status }
            });
            
            // 触发成员可用/不可用事件
            if (memberStatus === MemberStatus.Alive) {
              this.emitEvent({
                type: ClusterProviderEventType.MemberAvailable,
                member,
                timestamp: Date.now()
              });
            } else {
              this.emitEvent({
                type: ClusterProviderEventType.MemberUnavailable,
                member,
                timestamp: Date.now()
              });
            }
          }
        } else {
          // 新成员加入
          this.members.set(nodeId, member);
          
          // 触发成员加入事件
          this.emitEvent({
            type: ClusterProviderEventType.MemberJoined,
            member,
            timestamp: Date.now()
          });
          
          // 如果成员状态为可用，触发可用事件
          if (memberStatus === MemberStatus.Alive) {
            this.emitEvent({
              type: ClusterProviderEventType.MemberAvailable,
              member,
              timestamp: Date.now()
            });
          }
        }
      }
      
      // 处理成员离开
      const currentNodeIds = new Set(clusterServices.map(svc => svc.Meta?.nodeId).filter(Boolean));
      for (const [nodeId, member] of this.members.entries()) {
        // 跳过本地节点
        if (nodeId === this.localNodeId) continue;
        
        if (!currentNodeIds.has(nodeId) && member.status !== MemberStatus.Dead) {
          // 更新状态为离线
          member.status = MemberStatus.Dead;
          this.members.set(nodeId, member);
          
          // 触发成员不可用事件
          this.emitEvent({
            type: ClusterProviderEventType.MemberUnavailable,
            member,
            timestamp: Date.now()
          });
          
          // 触发成员离开事件
          this.emitEvent({
            type: ClusterProviderEventType.MemberLeft,
            member,
            timestamp: Date.now()
          });
          
          // 延迟移除成员
          setTimeout(() => {
            this.members.delete(nodeId);
          }, 5000);
        }
      }
    } catch (error) {
      console.error('刷新成员列表失败:', error);
    }
  }

  /**
   * 刷新领导者信息
   */
  private async refreshLeader(): Promise<void> {
    try {
      const result = await this.consulClient.kv_get(`${this.keyPrefix}leader`);
      if (result && result.Value) {
        const leaderId = result.Value;
        
        // 如果领导者变更，触发事件
        if (this.leaderId !== leaderId) {
          this.leaderId = leaderId;
          
          this.emitEvent({
            type: ClusterProviderEventType.LeaderElected,
            leaderId,
            timestamp: Date.now()
          });
        }
      } else {
        // 没有领导者，尝试选举
        await this.electLeader();
      }
    } catch (error) {
      console.error('刷新领导者信息失败:', error);
    }
  }

  /**
   * 尝试选举领导者
   */
  private async electLeader(): Promise<void> {
    if (!this.localNodeId || !this.sessionId) {
      return;
    }
    
    try {
      // 尝试获取领导者锁
      const result = await this.consulClient.kv_set(
        `${this.keyPrefix}leader`,
        this.localNodeId,
        { acquire: this.sessionId }
      );
      
      if (result) {
        // 成功获取锁，成为领导者
        this.leaderId = this.localNodeId;
        
        // 触发领导者选举事件
        this.emitEvent({
          type: ClusterProviderEventType.LeaderElected,
          leaderId: this.leaderId,
          timestamp: Date.now()
        });
        
        console.log(`节点 ${this.localNodeId} 成为领导者`);
      } else {
        // 未获取锁，刷新领导者信息
        await this.refreshLeader();
      }
    } catch (error) {
      console.error('选举领导者失败:', error);
    }
  }

  /**
   * 发送事件给所有监听器
   * @param event 事件对象
   */
  private emitEvent(event: ClusterProviderEvent): void {
    this.eventListeners.forEach(listener => {
      try {
        listener(event);
      } catch (error) {
        console.error('处理事件监听器失败:', error);
      }
    });
  }
} 